# LazyList

Коллекции Scala также включают [LazyList](https://scala-lang.org/api/3.x/scala/collection/immutable/LazyList.html),
который представляет собой ленивый неизменяемый связанный список.
Он называется «ленивым» — или нестрогим — потому что вычисляет свои элементы только тогда, когда они необходимы.
Поэтому ленивый список может быть бесконечно длинным. 
Обрабатываются только те элементы, которые запрашиваются. 
В остальном у ленивых списков те же параметры производительности, что и обычных.

Если списки создаются с помощью оператора `::`, то ленивые списки создаются схожей операцией `#::`. 
Вот простой пример ленивого списка с целыми числами 1, 2 и 3:

```dotty
val lazyList = 1 #:: 2 #:: 3 #:: LazyList.empty
// lazyList: LazyList[Int] = LazyList(1, 2, 3)
lazyList.toString
// res0: String = "LazyList(<not computed>)"
```

На первом месте в этом ленивом списке - `1`, затем - `2` и `3`. 
Но ни один из элементов не выводится, потому что список еще не вычислен! 
Ленивые списки задуманы обрабатываться лениво, поэтому метод `toString` не выводит элементов, 
не производя дополнительные вычисления.

Ещё примеры:

```dotty
val x = LazyList.range(1, Int.MaxValue)
x.take(1)    
x.take(5)    
x.map(_ + 1) 
```

`LazyList` начинает вычислять свои элементы только при вызове некоторых методов, например, `foreach`:

```dotty
x.take(1).foreach(println)
// 1
```

##### Последовательность Фибоначчи

Пример ленивого списка, 
содержащего [последовательность Фибоначчи](https://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B0_%D0%A4%D0%B8%D0%B1%D0%BE%D0%BD%D0%B0%D1%87%D1%87%D0%B8). 

```dotty
def fibFrom(a: Int, b: Int): LazyList[Int] = a #:: fibFrom(b, a + b)
```

Эта функция обманчиво проста. 
Первый элемент очевидно `a`, остальная часть - 
это последовательность Фибоначчи, начинающаяся с `b`, за которой следует `a + b`. 
Сложность состоит в том, как вычислить эту последовательность, не вызывая бесконечной рекурсии. 
Если бы функция использовала `::` вместо `#::`, то каждый вызов функции приводил бы к очередному вызову, 
вызывая тем самым бесконечную рекурсию. 
Но так как используется `#::`, то вычисление правой части не производится до тех пор, пока она не будет запрошена.

Ниже приведены первые элементы последовательности Фибоначчи, начиная с двух едениц:

```dotty
val fibs = fibFrom(1, 1).take(7)
// fibs: LazyList[Int] = LazyList(1, 1, 2, 3, 5, 8, 13)
fibs.toList
// res5: List[Int] = List(1, 1, 2, 3, 5, 8, 13)
```


### Детали

Для получения дополнительной информации об использовании, преимуществах и недостатках
строгих и нестрогих (ленивых) коллекций см.
обсуждение "строгих" и "нестрогих" коллекций на странице
["Архитектура Scala 2.13’s Collections"](https://docs.scala-lang.org/overviews/core/architecture-of-scala-213-collections.html).


---

**Ссылки:**

- [Scala3 book](https://docs.scala-lang.org/scala3/book/taste-collections.html)
- [Scala3 book, Collections Types](https://docs.scala-lang.org/scala3/book/collections-classes.html)
- [Scala, Immutable collections](https://docs.scala-lang.org/ru/overviews/collections-2.13/concrete-immutable-collection-classes.html)
